﻿using System;
using Server;
using Server.Spells;
using Server.Mobiles;


namespace Server.Items
{
    public class ArmaRangedBase : ArmaBase
    {
        public virtual int EffectID { get { return 0xF42; } }
        public virtual Type AmmoType { get { return typeof(Arrow); } }
        public virtual Item Ammo { get { return new Arrow(); } }
		
        public override WeaponAnimation DefAnimazione { get { return WeaponAnimation.ShootBow; } }
		public override Layer DefLayer { get { return Layer.TwoHanded; } }


        public override SkillName DefSkillUtilizzata { get { return SkillName.Archery; } }
        public override WeaponType DefTipo { get { return WeaponType.Ranged; } }

        private Timer m_RecoveryTimer; // so we don't start too many timers
        private bool m_Balanced;
        private int m_Velocity;

        [CommandProperty(AccessLevel.GameMaster)]
        public bool Balanced
        {
            get { return m_Balanced; }
            set { m_Balanced = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int Velocity
        {
            get { return m_Velocity; }
            set { m_Velocity = value; InvalidateProperties(); }
        }

        public ArmaRangedBase(int itemID) : base(itemID)
        {
            // TODO: sempre questo layer?
            Layer = Layer.TwoHanded;
        }

        public ArmaRangedBase(Serial serial)
            : base(serial)
        {
        }

        public override double StartSwingMovement(Mobile attacker, Mobile defender)
        {
            if (OnFired(attacker, defender))
                return base.StartSwingMovement(attacker, defender);
            else
            {
                attacker.SendMessage("Non hai frecce o dardi");
                return -1.0;
            }
        }

        public override TimeSpan OnSwing(Mobile attacker, Mobile defender)
        {
            WeaponAbility a = WeaponAbility.GetCurrentAbility(attacker);

            if (attacker.HarmfulCheck(defender))
            {
                //if (OnFired(attacker, defender))
                //{
                    bool hit;
                    double bonusOrMalus = 0.0;

                    // Aggiusta la direzione dell'attaccante a meno che i due PG sono sullo stesso tile.
                    if (!attacker.InRange(defender, 0))
                        attacker.aggiornaDirezioneDuranteCaricaScarica(defender, true);

                    attacker.DisruptiveAction();

                    attacker.MovingEffect(defender, EffectID, 18, 1, false, false);

                    //attacker.Send( new Swing( 0, attacker, defender ) );	

                    // Se il bersaglio e' ad un tile di distanza, c'e un malus nel colpire.
                    // TODO: quant'e di preciso? Per ora 8% valore arbitrario
                    if (attacker.InRange(defender, 1))
                        bonusOrMalus = bonusOrMalus - 8.0;

                    // I due PG sono sullo stesso tile, perdi il colpo.
                    if (attacker.InRange(defender, 0))
                    {
                        attacker.SendMessage("Sei troppo vicino, non riesci a prendere la mira");
                        hit = false;
                    }
                    // L'attaccante non si e' mosso
                    else if (attacker.m_PassiMentreCaricoIlColpo == 0)
                    {
                        hit = CheckHit(attacker, defender, bonusOrMalus);
                    }
                    // L'attaccante si e' mosso di al piu 6 tile (10% di malus a colpire)
                    else if (attacker.m_PassiMentreCaricoIlColpo <= 6)
                    {
                        bonusOrMalus = bonusOrMalus - 10.0;
                        hit = CheckHit(attacker, defender, bonusOrMalus);
                    }
                    // Perdi il colpo, l'attaccante si e' mosso di piu' di 6 tile.
                    else
                    {
                        attacker.SendMessage("Ti sei mosso troppo, perdi la mira");
                        attacker.SendMessage("DEBUG: Hai corso per {0} tile", attacker.m_PassiMentreCaricoIlColpo);
                        hit = false;
                    }

                    if (hit)
                        OnHit(attacker, defender);
                    else
                        OnMiss(attacker, defender);
                //}
                //else
                //{
                //    attacker.SendMessage("Non hai frecce o dardi");
                //}
            }

            attacker.RevealingAction();

            return GetDelay(attacker);
        }

        public override void OnHit(Mobile attacker, Mobile defender, double damageBonus)
        {
            // Metti la freccia nello zaino del defender
            if (attacker.Player && !defender.Player && (defender.Body.IsAnimal || defender.Body.IsMonster) && 0.4 >= Utility.RandomDouble())
                defender.AddToBackpack(Ammo);

            base.OnHit(attacker, defender, damageBonus);
        }

        public override void OnMiss(Mobile attacker, Mobile defender)
        {
            if (attacker.Player && 0.4 >= Utility.RandomDouble())
            {
                if (Core.SE)
                {
                    PlayerMobile p = attacker as PlayerMobile;

                    if (p != null)
                    {
                        Type ammo = AmmoType;

                        if (p.RecoverableAmmo.ContainsKey(ammo))
                            p.RecoverableAmmo[ammo]++;
                        else
                            p.RecoverableAmmo.Add(ammo, 1);

                        if (!p.Warmode)
                        {
                            if (m_RecoveryTimer == null)
                                m_RecoveryTimer = Timer.DelayCall(TimeSpan.FromSeconds(10), new TimerCallback(p.RecoverAmmo));

                            if (!m_RecoveryTimer.Running)
                                m_RecoveryTimer.Start();
                        }
                    }
                }
                else
                {
                    Ammo.MoveToWorld(new Point3D(defender.X + Utility.RandomMinMax(-1, 1), defender.Y + Utility.RandomMinMax(-1, 1), defender.Z), defender.Map);
                }
            }

            base.OnMiss(attacker, defender);
        }

        public virtual bool OnFired(Mobile attacker, Mobile defender)
        {
            // La faretra!
            BaseQuiver quiver = attacker.FindItemOnLayer(Layer.Cloak) as BaseQuiver;
            Container pack = attacker.Backpack;

            if (attacker.Player)
            {
                if (quiver == null || quiver.LowerAmmoCost == 0 || quiver.LowerAmmoCost > Utility.Random(100))
                {
                    if (quiver != null && quiver.ConsumeTotal(AmmoType, 1))
                        quiver.InvalidateWeight();
                    else if (pack == null || !pack.ConsumeTotal(AmmoType, 1))
                        return false;
                }
            }

            return true;
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            writer.Write((int)3); // version

            writer.Write((bool)m_Balanced);
            writer.Write((int)m_Velocity);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadInt();

            switch (version)
            {
                case 3:
                    {
                        m_Balanced = reader.ReadBool();
                        m_Velocity = reader.ReadInt();

                        goto case 2;
                    }
                case 2:
                case 1:
                    {
                        break;
                    }
                case 0:
                    {
                        /*m_EffectID =*/
                        reader.ReadInt();
                        break;
                    }
            }
        }
    }

    
}
